package mosdi.tests;

import static org.junit.Assert.assertArrayEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;
import mosdi.matching.BackwardOracleMatcher;
import mosdi.matching.Matcher;
import mosdi.util.Alphabet;
import mosdi.util.iterators.SegmentIterator;

public class SegmentIteratorTest extends TestCase {

	public static void assertSegment(int[] expected, SegmentIterator.Segment segment, List<int[]> strings, Matcher matcher) {
		assertArrayEquals(expected, segment.getSegment());
		assertEquals(expected.length, segment.length());
		assertArrayEquals(expected, Arrays.copyOfRange(strings.get(segment.getStringIndex()), segment.getStartPosition(), segment.getEndPosition()));
		assertEquals(matcher.findMatches(expected), segment.getPatternCount());
	}

	public void testIterator() {
		Alphabet alphabet = Alphabet.getDnaAlphabet();
		List<int[]> strings = new ArrayList<int[]>();
		strings.add(alphabet.buildIndexArray("GAAAGGTTTTTCCACATTGCCAGGATCTACCCACGTTCTTTGTCTGACCTCATATTGCAAGTCTAGACACTTTCAGTGAATTGTCGTAGATTATTTGAAGTCAAACCTCAGATAGTGAGGGCATAATGAACACAATGATGTCTCATGCACCATTCGACAATAGCTGCAAATTTTTGAGTTTAAAGTGTATTATTCTCACT"));
		strings.add(alphabet.buildIndexArray("AGTCACAAAGGTCTGGCAAAGCCAAGAATGTTTGAAAAGATATTAAATTTGTAGATATAAAGATACCAAGAACTTACATTTCATACTCCACAGGAGACAACATACTTAGCCTATTCTACCATATAAGTATGTGAATTATTAAATATATACTTATAGAAGTTAAATGCAGGGTGGCTGAGAAGGAGAGCGA"));
		strings.add(alphabet.buildIndexArray("GATTAGGCTACCTCCAAAAGGGCCAATGTCCTGCTTTTGCTCAGTCTAATTGTTGGCTGAAAGGCACCTAGTTCCCAGGTAATATAAAGATCCTTTATGAGAAGGCAGAGTTCTCTGTGATCAGCCCACAAATGCAATATGGGGTGAGACATGAGAGAGTCTTAATCTCTGTCAGCCCAACCTTTGATCACGCCCTGGG"));
		strings.add(alphabet.buildIndexArray("TTGACCCTTTCCTTTTCTGGCTGTTTCCTCATTTCCCCACCTCACACTTAAGGGACGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACGAGGGCGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCGTCAGAAAA"));
		strings.add(alphabet.buildIndexArray("TTTCAAGGTCACAGTGAAATGAATCGTGCTGTGATTCCCCTGCCACCATCACACATAAATTTATGAAAAATTAATCTCTTTGTAAATTATTCATGTGCTTGGGTCACTACAAGAGCACCAGCACCCTCAAATACAAACATAAAAATGCTAATGCGTCTGTTTTAATTTTGCAG"));
		strings.add(alphabet.buildIndexArray("GTGGCAACCTGTATGATGACTAAAAATGTGTCAGCCAACAGCTGCTACAAAGGATGGAATTTAATATTGTGGAATGTAGTATAAATACTTCCTGCTCAGAGGGGGTGAGAAGAAACCATATACTGTTATAATTCTTGTTTAGCCACCATTAATTCCCATTA"));
		int[] pattern = alphabet.buildIndexArray("CG");
		Matcher matcher = new BackwardOracleMatcher(alphabet.size(), pattern);
		SegmentIterator iterator = new  SegmentIterator(alphabet.size(), strings, pattern);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGAGGGCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGTTCTTTGTCTGACCTCATATTGCAAGTCTAGACACTTTCAGTGAATTGTCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGAGGGCGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACGAGGGCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGTAGATTATTTGAAGTCAAACCTCAGATAGTGAGGGCATAATGAACACAATGATGTCTCATGCACCATTCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGTTCTTTGTCTGACCTCATATTGCAAGTCTAGACACTTTCAGTGAATTGTCGTAGATTATTTGAAGTCAAACCTCAGATAGTGAGGGCATAATGAACACAATGATGTCTCATGCACCATTCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGTGCTGTGATTCCCCTGCCACCATCACACATAAATTTATGAAAAATTAATCTCTTTGTAAATTATTCATGTGCTTGGGTCACTACAAGAGCACCAGCACCCTCAAATACAAACATAAAAATGCTAATGCG"), iterator.next(), strings, matcher);
		assertTrue(iterator.hasNext());
		assertSegment(alphabet.buildIndexArray("CGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACGAGGGCGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCG"), iterator.next(), strings, matcher);
		assertFalse(iterator.hasNext());
	}
	
	public static void assertSegmentWeighted(int[] expected, SegmentIterator.Segment segment, List<int[]> strings, Matcher matcher, int weight) {
		assertArrayEquals(expected, segment.getSegment());
		assertEquals(expected.length, segment.length());
		assertArrayEquals(expected, Arrays.copyOfRange(strings.get(segment.getStringIndex()), segment.getStartPosition(), segment.getEndPosition()));
		assertEquals(weight, segment.getPatternCount());
	}

	public void testIteratorWeighted() {
		Alphabet alphabet = Alphabet.getDnaAlphabet();
		List<int[]> strings = new ArrayList<int[]>();
		strings.add(alphabet.buildIndexArray("GAAAGGTTTTTCCACATTGCCAGGATCTACCCACGTTCTTTGTCTGACCTCATATTGCAAGTCTAGACACTTTCAGTGAATTGTCGTAGATTATTTGAAGTCAAACCTCAGATAGTGAGGGCATAATGAACACAATGATGTCTCATGCACCATTCGACAATAGCTGCAAATTTTTGAGTTTAAAGTGTATTATTCTCACT"));
		strings.add(alphabet.buildIndexArray("AGTCACAAAGGTCTGGCAAAGCCAAGAATGTTTGAAAAGATATTAAATTTGTAGATATAAAGATACCAAGAACTTACATTTCATACTCCACAGGAGACAACATACTTAGCCTATTCTACCATATAAGTATGTGAATTATTAAATATATACTTATAGAAGTTAAATGCAGGGTGGCTGAGAAGGAGAGCGA"));
		strings.add(alphabet.buildIndexArray("GATTAGGCTACCTCCAAAAGGGCCAATGTCCTGCTTTTGCTCAGTCTAATTGTTGGCTGAAAGGCACCTAGTTCCCAGGTAATATAAAGATCCTTTATGAGAAGGCAGAGTTCTCTGTGATCAGCCCACAAATGCAATATGGGGTGAGACATGAGAGAGTCTTAATCTCTGTCAGCCCAACCTTTGATCACGCCCTGGG"));
		strings.add(alphabet.buildIndexArray("TTGACCCTTTCCTTTTCTGGCTGTTTCCTCATTTCCCCACCTCACACTTAAGGGACGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACGAGGGCGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCGTCAGAAAA"));
		strings.add(alphabet.buildIndexArray("TTTCAAGGTCACAGTGAAATGAATCGTGCTGTGATTCCCCTGCCACCATCACACATAAATTTATGAAAAATTAATCTCTTTGTAAATTATTCATGTGCTTGGGTCACTACAAGAGCACCAGCACCCTCAAATACAAACATAAAAATGCTAATGCGTCTGTTTTAATTTTGCAG"));
		strings.add(alphabet.buildIndexArray("GTGGCAACCTGTATGATGACTAAAAATGTGTCAGCCAACAGCTGCTACAAAGGATGGAATTTAATATTGTGGAATGTAGTATAAATACTTCCTGCTCAGAGGGGGTGAGAAGAAACCATATACTGTTATAATTCTTGTTTAGCCACCATTAATTCCCATTA"));
		int[] pattern = alphabet.buildIndexArray("CG");
		Matcher matcher = new BackwardOracleMatcher(alphabet.size(), pattern);
		List<int[]> occurrences = new ArrayList<int[]>();
		for (int[] s : strings) occurrences.add(matcher.findAllMatchPositions(s));
		int[] w0 = {1,3,5}; 
		int[] w1 = {7}; 
		int[] w2 = {1};
		int[] w3 = {9,2,4,8}; 
		int[] w4 = {8,7};
		int[] w5 = {};
		List<int[]> weights = new ArrayList<int[]>();
		weights.add(w0);
		weights.add(w1);
		weights.add(w2);
		weights.add(w3);
		weights.add(w4);
		weights.add(w5);
		SegmentIterator iterator = new  SegmentIterator(alphabet.size(), strings, pattern.length, occurrences, weights);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGAGGGCG"), iterator.next(), strings, matcher, 6);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGTTCTTTGTCTGACCTCATATTGCAAGTCTAGACACTTTCAGTGAATTGTCG"), iterator.next(), strings, matcher, 4);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCG"), iterator.next(), strings, matcher, 12);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACG"), iterator.next(), strings, matcher, 11);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGAGGGCGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCG"), iterator.next(), strings, matcher, 14);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACGAGGGCG"), iterator.next(), strings, matcher, 15);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGTAGATTATTTGAAGTCAAACCTCAGATAGTGAGGGCATAATGAACACAATGATGTCTCATGCACCATTCG"), iterator.next(), strings, matcher, 8);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGTTCTTTGTCTGACCTCATATTGCAAGTCTAGACACTTTCAGTGAATTGTCGTAGATTATTTGAAGTCAAACCTCAGATAGTGAGGGCATAATGAACACAATGATGTCTCATGCACCATTCG"), iterator.next(), strings, matcher, 9);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGTGCTGTGATTCCCCTGCCACCATCACACATAAATTTATGAAAAATTAATCTCTTTGTAAATTATTCATGTGCTTGGGTCACTACAAGAGCACCAGCACCCTCAAATACAAACATAAAAATGCTAATGCG"), iterator.next(), strings, matcher, 15);
		assertTrue(iterator.hasNext());
		assertSegmentWeighted(alphabet.buildIndexArray("CGGAAGGCAGCAGAATTGTAGACCCCTTTGAAAATTCTAATCATAGTTATCTATTACAAAAGACGAGGGCGGCAGTCACCAACAGAGATTTCCAGGAGAGACAGTAAGCACAAGAACAGGCAGCTGGGTTCG"), iterator.next(), strings, matcher, 23);
		assertFalse(iterator.hasNext());
	}

}
